home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 2 / Gold Medal Software Volume 2 (Gold Medal) (1994).iso / prog / asm_n_z.arj / TOUCHE.ASM < prev    next >
Assembly Source File  |  1986-06-01  |  19KB  |  653 lines

  1.     page 58,132
  2.     title TOUCHE -- A File Date Maintenance Utility
  3.     name TOUCHE
  4.  
  5. comment    *
  6.     
  7.     This program will change the date/time stamp of all files on its 
  8.     command line to the current date and time.
  9.     
  10.     See TOUCHE.DOC for instructions on how to use this program.
  11.     
  12.     Copyright (c) 1986    Raymond Moon   ALL RIGHTS RESERVED
  13.     
  14.     *
  15.  
  16. ;----------------------------
  17. ;    Define the various macros used in this program.
  18.     
  19. @CLOSE    macro    FH            ;; DOS 2.0+ Close File/Device Macro
  20.     mov    bx,FH            ; Load File Handle into BX
  21.     mov    ah,3eh            ; Request DOS close File Handle
  22.     int    21h            ; Call PC-DOS
  23.     endm
  24.  
  25. @ENTRY    macro                ;; Standard Procedure Entry Logic
  26.     push    bp            ; Save BP
  27.     mov    bp,sp            ; Establish stack addressability
  28.     endm
  29.  
  30. @EXIT    macro    RTNCODE            ;; Terminate program with return code
  31.     mov    ax,4c&RTNCODE&h        ; Request term with return code
  32.     int    21h            ; Call PC-DOS
  33.     endm
  34.  
  35. @GETDATE macro                ;; Get Current Date Macro
  36.     mov    ah,2ah            ; Request DOS get current date
  37.     int    21h            ; Call PC-DOS
  38.     endm
  39.         
  40. @GETTIME macro                ;; Get Current Time Macro
  41.     mov    ah,2ch            ; Request DOS get current time
  42.     int    21h            ; Call PC-DOS
  43.     endm
  44.  
  45. @OPEN    macro    FILESPEC,MODE        ;; DOS 2.0+ Open File Macro
  46.     lea    dx,FILESPEC        ; Load addr of FILESPEC in DX
  47.     mov    ax,3D0&MODE&h        ; Request DOS open file with mode
  48.     int    21h            ; Call PC-DOS
  49.     endm
  50.     
  51. @WRITE    macro    STRING,FH        ;; DOS 2.0+ Write to File Macro
  52.     lea    dx,STRING        ; Load String addr in DX
  53.     mov    cx,STRING&_LEN        ; Load String Length in CX
  54.     mov    bx,FH            ; Load File Handle in BX
  55.     mov    ah,40h            ; Request DOS write to file/device
  56.     int    21h            ; Call PC-DOS
  57.     endm
  58.  
  59. ;----------------------------
  60. ;    Define various equates used in this program
  61.  
  62.     STDOUT    equ    1
  63.     STDERR    equ    2
  64.     TAB    equ    9
  65.         BLNK    equ     20h
  66.     LF    equ    0ah
  67.     CR    equ    0dh
  68.  
  69. ;----------------------------
  70. ;    Define the group and segments so that all will reside in one 64K
  71. ;    physical segment.
  72.  
  73. GRP    group    CSEG,DTA,DSEGB,DSEGA        ; All segments in same segment
  74.     assume    cs:GRP,ds:GRP,es:GRP,ss:GRP
  75.     
  76. DSEGB    segment byte public 'STRING'
  77.  
  78.     public LOGO, DOS_ERR, NOT_FOUND, TOUCHED, PROPER_USE, CANT
  79.     
  80. LOGO    db    'TOUCHE -- A File Date Maintenance Utility V1.00',CR,LF
  81.     db    'Copyright 1986 - MoonWare',CR,LF,LF
  82. LOGO_LEN equ    $ - LOGO
  83. DOS_ERR db    CR,LF,LF,'TOUCHE:  Need DOS 2.0+'
  84. NOT_FOUND db    ' -- Not Found',CR,LF
  85. NOT_FOUND_LEN equ $ - NOT_FOUND
  86. TOUCHED db    ' -- Touched',CR,LF
  87. TOUCHED_LEN equ $ - TOUCHED
  88. CANT    db    ' -- Cannot Touch',CR,LF
  89. CANT_LEN equ    $ - CANT
  90. PROPER_USE db    CR,LF,'TOUCHE:  Nothing to do.',CR,LF,LF,'Use:',CR,LF,LF,TAB
  91.     db    'touche file1.ext file2.ext . . . fileN.ext',CR,LF,LF,TAB
  92.     db    'Drive, Path, and Wildcards allowed in file names.',CR,LF,LF
  93. PROPER_USE_LEN equ $ - PROPER_USE
  94.     db    '***** 30 May 1986 -- Raymond Moon *****'
  95. DSEGB    ends
  96.  
  97. DSEGA    segment byte public 'DATA'
  98.     public    pDOS_ERR
  99. pDOS_ERR dw    offset GRP:DOS_ERR
  100. DSEGA    ends
  101.  
  102. ;----------------------------
  103. ;    Use 'Segment At' to create variable to access the information
  104. ;    contained in the DTA after First Find/Next Find DOS Function
  105. ;    call is used.
  106.     
  107. DTA    segment at 00h
  108.     public  FILENAME
  109.     
  110.     org    80h
  111.     
  112. RESERVED_DOS    db    21 dup (?)
  113. DTA_ATTRIB    db    ?
  114. DTA_TIME    dw    ?
  115. DTA_DATE    dw    ?
  116. DTA_SIZE_LO    dw    ?
  117. DTA_SIZE_HI    dw    ?
  118. FILENAME    db    13 dup (?)
  119. DTA    ends
  120.  
  121. ;----------------------------
  122. ;    Define structure to address argc and *argv[].
  123.  
  124. STACK_PARMS    struc
  125.     dw    ?,?            ; Saved BP & Return Address
  126. ARGC    dw    ?            ; Count of command line arguments
  127. ARGV    dw    ?            ; Address to command line arguments
  128. STACK_PARMS    ends
  129.  
  130.     
  131. CSEG    segment para public 'CODE'
  132.  
  133. ;-----------------------------
  134. ;    Define all procedures as public for debugging
  135.  
  136.     public MAIN, TOUCH_FILES, NOTHING_TO_DO, ISDOS2, FPUTS, STRCPY, STRLEN
  137.  
  138. ;-----------------------------
  139. ;    Define Command Line arguments located in the PSP
  140.  
  141.     org     80h
  142.     PARM_LEN db     ?
  143.     PARMS   db      127 dup(?)
  144.  
  145. ;-----------------------------
  146. ;    MAIN procedure parses the Command Line 
  147.  
  148.     org    100h            ; .COM file format
  149. MAIN    proc    far
  150.     push    pDOS_ERR        ; Pass addr of DOS_ERR
  151.     call    ISDOS2            ; Check to see if DOS is 2.0+ 
  152.     add    sp,2            ; Reset SP
  153.     cmp    PARM_LEN,0        ; Are there any Command Line arguments
  154.     jne    MN1            ; Yes, process them
  155.     call    NOTHING_TO_DO        ; No, go to Nothing_to_do 
  156. MN1:    xor    cx,cx            ; Null CX
  157.     push    cx            ; This ensures last *argv ends in NUL
  158.     mov    cl,PARM_LEN        ; Get # of bytes in Command Line
  159.     inc    cl            ; Increment CL to ensure round up
  160.     and    cx,0feh            ; Force an even count
  161.     mov    ax,sp            ; Get SP  
  162.     mov    bp,sp            ; Set BP to last byte of Cmd Ln
  163.     sub    ax,cx            ; Subtract PARM_LEN
  164.     mov    sp,ax            ; Reset SP, room on Stack
  165.     lea    si,PARMS        ; Load source addr in SI
  166.     mov    di,sp            ; Load destin addr in DI
  167.     cld                ; Ensure Direction Flag is up
  168.     rep    movsb            ; Move Command Line onto the Stack
  169.  
  170. ;-----------------------------
  171. ;    Convert all blanks in the Command Line to Nul
  172.  
  173.     mov    bx,bp            ; BX points to last byte of Cmd Ln
  174. MN2:    mov    al,[bx]            ; Get byte
  175.     cmp    al,BLNK            ; Is it a blank?
  176.     ja    MN3            ; No, go set up to get another
  177.     xor    al,al            ; Nul AX
  178.     mov    [bx],al            ; Store Nul in [BX]
  179. MN3:    dec    bx            ; BX point to next byte
  180.     cmp    bx,sp            ; Are we through yet?
  181.     jnb    MN2            ; No, go one mo' 'gin
  182.                     
  183. ;-----------------------------
  184. ;    Build *argv[].  argc kept in CX.  DX used as IN_WORD flag
  185.  
  186.     xor    cx,cx            ; Set CX (argc) to 0
  187.     xor    dx,dx            ; Set DX to NOT_INWORD
  188.     mov    bx,bp            ; BX point to last byte
  189.     mov    bp,sp            ; BP now points to Top of Stack
  190. MN4:    mov    al,[bx]            ; Get byte
  191.     cmp    al,0            ; Is it Nul?
  192.     jne    MN5            ; No, it is a char
  193.     cmp    dx,0            ; Was the last byte not a char?
  194.     je    MN6            ; Yes, go on with the processing
  195.     xor    dx,dx            ; No, it was a char.  Clear INWORD.
  196.     inc    cx            ; Increment argc
  197.     inc    bx            ; BX points to Cmd Ln arg
  198.     push    bx            ; Push addr onto stack
  199.     dec    bx            ; Reset BX
  200.     jmp    short MN6        ; Go set up for another byte
  201. MN5:    inc    dx            ; Set DX to INWORD     
  202. MN6:    dec    bx            ; BX point to next byte
  203.     cmp    bx,bp            ; Are we at the 1st byte yet?
  204.     jnb    MN4            ; No, go process another
  205.  
  206. ;-----------------------------
  207. ;    Set up for and call TOUCH_FILES
  208.  
  209.     push    cx            ; Push ARGC onto stack
  210.     call    TOUCH_FILES        ; Process files
  211. MAIN    endp
  212.  
  213. ;----------------------------
  214. ;    This procedure prints the string PROPER_USE then terminates the 
  215. ;    program.
  216.  
  217. NOTHING_TO_DO proc near
  218.     @WRITE    PROPER_USE,STDERR    ; Tell the user how to use TOUCH
  219.     @EXIT    01            ; Exit with return code of 1
  220. NOTHING_TO_DO endp
  221.  
  222. ;----------------------------
  223. ;    Process each filename one at a time.
  224.  
  225. TOUCH_FILES    proc near
  226.     @ENTRY                ; Std Entry Logic
  227.     sub    sp,75            ; Make room for automatic variables
  228.     
  229. TF_BASE equ    [bp - 75]        ; Automatic variable addressing base
  230.  
  231. TF_AUTO    struc                ; Automatic variable structure
  232. DATE    dw    ?
  233. TIME    dw    ?
  234. COUNT    dw    ?
  235. LENGTH    dw    ?
  236. FILE_HANDLE dw    ?
  237. PATH_END dw    ?
  238. FILESPEC db    63 dup (?)
  239. TF_AUTO    ends
  240.     
  241. ;----------------------------
  242. ;    Display logo
  243.  
  244.     @WRITE LOGO,STDOUT
  245.     
  246. ;----------------------------
  247. ;    Get the time and date.  Convert these into DOS file date/time stamp
  248. ;    format.
  249.  
  250.     @GETDATE            ; Get the DOS date
  251.     xor    ax,ax            ; Nul AX
  252.     sub    cx,1980            ; Convert #years into DOS file format
  253.     xchg    ch,cl            ; Move year into CH
  254.     shl    ch,1            ; Convert year into DOS file format
  255.     or    ah,ch            ; Move it into AX
  256.     xor    bx,bx            ; Nul BX
  257.     mov    bh,dh            ; Month into BX
  258.     shr    bx,1
  259.     shr    bx,1
  260.     shr    bx,1            ; Convert month into DOS file format
  261.     or    ax,bx            ; Move it into AX
  262.     or    al,dl            ; Move seconds into AX
  263.     mov    TF_BASE.DATE,ax        ; Save it
  264.     
  265. ;----------------------------
  266. ;    Get the time and convert it.
  267.  
  268.     @GETTIME            ; Get the DOS time
  269.     xor    ax,ax            ; Nul AX
  270.     xor    bx,bx            ; Nul BX
  271.     shl    ch,1
  272.     shl    ch,1
  273.     shl    ch,1            ; Convert hour into DOS file format
  274.     or    ah,ch            ; Move it into AX
  275.     mov    bh,cl            ; Move minutes into BH
  276.     shr    bx,1
  277.     shr    bx,1
  278.     shr    bx,1            ; Convert minutes into DOS file format
  279.     or    ax,bx            ; Move it into AX
  280.     or    al,dh            ; Move seconds into AX
  281.     mov    TF_BASE.TIME,ax        ; Save it
  282.     
  283. ;----------------------------
  284. ;    Set Count to zero.
  285.  
  286.     xor    ax,ax            ; Nul AX
  287.     mov    TF_BASE.COUNT,ax    ; Set count to zero
  288.     
  289. ;----------------------------
  290. ;    Process next file in command line.  Start by stripping off any drive
  291. ;    and path and save it in filespec.  Start by putting pointer to next
  292. ;    into DI
  293.  
  294. TF1:    mov    di,TF_BASE.COUNT    ; Get next arg number
  295.     shl    di,1            ; Convert it to a word pointer
  296.     mov    di,[bp].ARGV[di]    ; Load pointer to next filename in DI
  297.     
  298. ;----------------------------
  299. ;    Determine string length
  300.  
  301.     push    di            ; Pass address of string and save it
  302.     push    di
  303.     call    STRLEN            ; Get string length
  304.     add    sp,2            ; Restore SP
  305.     mov    TF_BASE.LENGTH,ax    ; Save length
  306.     inc    TF_BASE.LENGTH        ; Ensure search goes far enough
  307.     
  308. ;----------------------------
  309. ;    Set up for reverse search
  310.  
  311.     std                ; Set direction flag for reverse search
  312.     pop    di
  313.     push    di            ; Restore address of filename
  314.     add    di,ax            ; Add length
  315.     mov    TF_BASE.PATH_END,di    ; Save end of string address
  316.     
  317. ;----------------------------
  318. ;    Search for last occurrance of '\'.
  319.  
  320.     mov    cx,TF_BASE.LENGTH    ; Length of search in CX
  321.     mov    al,'\'            ; Load backslash in AL
  322.     repne    scasb            ; Find it
  323.     jcxz    TF2            ; If not found, do not increment DI
  324.     inc    di            ; DI => '\' or 1st char if not found
  325. TF2:    mov    si,di            ; Save it
  326.  
  327. ;----------------------------
  328. ;    Search for last occurance of ':'
  329.  
  330.     mov    cx,TF_BASE.LENGTH    ; Length of search in CX
  331.     mov    di,TF_BASE.PATH_END    ; Load addr of last char in filename
  332.     mov    al,':'            ; Load colon in AL
  333.     repne    scasb            ; Find it
  334.     jcxz    TF3            ; If not found, do not increment DI
  335.     inc    di            ; DI => ':' or 1st char if not found
  336.     
  337. ;----------------------------
  338. ;    Compare the tow occurrances to find which occurred last.  If equal,
  339. ;    neither was found and DI => 1st char.
  340.  
  341. TF3:    cld                ; Clear direction flag
  342.     cmp    di,si            ; Is DI = backslach position?
  343.     je    TF5            ; Yes, neither found, continue.
  344.     ja    TF4            ; Is ':' > '\'?, 
  345.     mov    di,si            ; No, load '\' position into DI
  346.         
  347. ;----------------------------
  348. ;    Copy drive/path into FILESPEC.  Then set PATH_END to path's end in
  349. ;    FILESPEC.
  350.  
  351. TF4:    inc    di            ; DI => 1st char
  352.     mov    cx,di            ; Move end of path in CX
  353.     pop    di
  354.     push    di            ; Restore DI to address of filespec
  355.     sub    cx,di            ; CX = length of drive/path info
  356.     mov    si,di            ; Move address of filename into SI
  357.     lea    di,TF_BASE.FILESPEC    ; Move address of FILESPEC into DI
  358.     mov    ax,cx            ; Mov length of drive/path into into AX
  359.     add    ax,di            ; Calculate new PATH_END
  360.     mov    TF_BASE.PATH_END,ax    ; Save it
  361.     rep    movsb            ; Move drive/path into filespec
  362.     jmp    short TF6        ; Jump to First Find code
  363.         
  364. ;----------------------------
  365. ;    Since ':' position = '\' position, neither was found. Set PATH_END
  366. ;    to 1st char in FILESPEC
  367.  
  368. TF5:    lea    di,TF_BASE.FILESPEC    ; Get addr of FILESPEC
  369.     mov    TF_BASE.PATH_END,di    ; Save it
  370.     jmp    short TF6        ; Skip drive/path processing code
  371.     
  372. ;----------------------------
  373. ;    Now FILESPEC contains any drive and path name. PATH_END points to
  374. ;     first open position to load file names    return from FIRST FIND/
  375. ;    NEXT FIND DOS functions.  Start performing searches.
  376.  
  377. TF6:    pop    dx            ; Load filename addr in DX
  378.     push    dx            ; Save it again
  379.     mov    cl,03h            ; Find all Normal, Read-Only, Hidden
  380.     mov    ah,4eh            ; Request DOS start search
  381.     int    21h            ; Call PC-DOS
  382.     jnc    TF7            ; Something found, process it
  383.     
  384. ;----------------------------
  385. ;    If the program fell through here, no matching files found. Tell the 
  386. ;    user. Address of filename is still on the stack.
  387.  
  388.     mov    ax,STDERR        ; load STDERR file handle in AX
  389.     push    ax            ; Pass it
  390.     call    FPUTS            ; Display filename
  391.     add    sp,4            ; Reset stack
  392.     @WRITE    NOT_FOUND,STDERR    ; Display what happened
  393.     jmp     TF12            ; Jump to End of Loop test logic
  394.     
  395. ;----------------------------
  396. ;    File found.  Set up filespec for file opening DOS Call.
  397.  
  398. TF7:    add    sp,2            ; Remove filename addr
  399. TF8:    lea    ax,FILENAME        ; Load filename in AX
  400.     push    ax            ; Pass it
  401.     push    TF_BASE.PATH_END    ; Pass destination addr
  402.     call    STRCPY            ; Copy it
  403.     add    sp,4            ; Restore stack
  404.  
  405. ;----------------------------
  406. ;    Now open file.
  407.  
  408.     @OPEN    TF_BASE.FILESPEC,0    ; Open file for read-only
  409.     jnc    TF9            ; Opened successfully, continue
  410.     
  411. ;----------------------------
  412. ;    Tell user that file can't be touched.
  413.  
  414.     lea    dx,TF_BASE.FILESPEC    ; Load address of filespec in DX
  415.     push    dx            ; Pass it
  416.     mov    ax, STDERR        ; Load STDERR file handle in AX
  417.     push    ax            ; Pass it
  418.     call    FPUTS            ; Display filespec name
  419.     add    sp,4            ; Restore stack
  420.     @WRITE    CANT,STDERR        ; Tell user what happened
  421.     jmp    short TF11        ; Go process another
  422.     
  423. ;----------------------------
  424. ;    Touch file.
  425.  
  426. TF9:    mov    TF_BASE.FILE_HANDLE,ax    ; Save file handle
  427.     mov    bx,ax            ; Move file handle into BX
  428.     mov    cx,TF_BASE.TIME        ; Load time stamp into CX
  429.     mov    dx,TF_BASE.DATE        ; Load date stamp into DX
  430.     mov    ax,5701h        ; Request DOS set file date/time stamp
  431.     int    21h            ; Call PC-DOS
  432.     jnc    TF10            ; successful, tell user
  433.         
  434. ;----------------------------
  435. ;    Tell user that file can't be touched.
  436.  
  437.     lea    dx,TF_BASE.FILESPEC    ; Load address of filespec in DX
  438.     push    dx            ; Pass it
  439.     mov    ax, STDERR        ; Load STDERR file handle in AX
  440.     push    ax            ; Pass it
  441.     call    FPUTS            ; Display filespec name
  442.     add    sp,4            ; Restore stack
  443.     @WRITE    CANT,STDERR        ; Tell user what happened
  444.     @CLOSE    TF_BASE.FILE_HANDLE    ; Close file
  445.     jmp    short TF11        ; Go process another
  446.     
  447. ;----------------------------
  448. ;    Tell user that file successfully touched.
  449.  
  450. TF10:    lea    dx,TF_BASE.FILESPEC    ; Load address of filespec in DX
  451.     push    dx            ; Pass it
  452.     mov    ax, STDOUT        ; Load STDOUT file handle in AX
  453.     push    ax            ; Pass it
  454.     call    FPUTS            ; Display filespec name
  455.     add    sp,4            ; Restore stack
  456.     @WRITE    TOUCHED,STDOUT        ; Tell user what happened
  457.     @CLOSE    TF_BASE.FILE_HANDLE    ; Close file
  458.     
  459. ;----------------------------
  460. ;    Try to find another file with same filespec
  461.  
  462. TF11:    mov    ah,4fh            ; Continue search
  463.     int    21h            ; Call PC-DOS
  464.     jc    TF12            ; No find, go see if any more
  465.     jmp    TF8            ; Process this find
  466.     
  467. ;---------------------------
  468. ;    When the programs falls through here, no further files were found,
  469. ;    or no matching files were found on first search.  Increment count
  470. ;    and see if there are any other filenames left on the command line.
  471.  
  472. TF12:    inc    TF_BASE.COUNT        ; Increment count
  473.     mov    ax,TF_BASE.COUNT    ; Get count of file processed
  474.     cmp    ax,[bp].ARGC        ; Are there any more?
  475.     jae    TF13            ; Done
  476.     jmp    TF1            ; Not done, go process another
  477.  
  478. ;----------------------------
  479. ;    Done. Terminate program with a return code of zero.
  480.  
  481. TF13:    @EXIT    00            ; Terminate
  482.  
  483. TOUCH_FILES endp
  484.  
  485. ;-----------------------------
  486. ;    Print ASCIIZ string to the passed file handle
  487.  
  488. FPUTS_PARMS    struc            ; Passed parameters structure
  489.     dw    ?,?            ; Saved BP, and return addr (IP)
  490. FILE_HAN dw    ?            ; File handle to be used
  491. OUTPUT    dw    ?            ; Addr of ASCIIZ string
  492. FPUTS_PARMS    ends
  493.  
  494. FPUTS    proc near
  495.     @ENTRY                ; Std entry logic
  496.  
  497. ;-----------------------------
  498. ;    Determine ASCIIZ string length
  499.  
  500.     mov    dx,[bp].OUTPUT        ; Load STRING addr in DX
  501.     mov    di,dx            ; Load STRING addr in DI
  502.     cld                ; Set direction flag foward
  503.     mov    cx,-1            ; Set CX to -1
  504.     xor    al,al            ; Nul AX
  505.     repne    scasb            ; Find Terminating Nul
  506.     not    cx            ; Convert CX to STRLEN
  507.     dec    cx            ; Remove NUL from STRLEN
  508.     push    cx            ; Save STRING length
  509.  
  510. ;-----------------------------
  511. ;    Set up for DOS Write to a file or device (Function 40h)
  512.  
  513.     mov    bx,[bp].FILE_HAN    ; Load file handle 
  514.     mov    ah,40h            ; Request DOS Device write
  515.     int    21h            ; Call PC-DOS
  516.  
  517. ;-----------------------------
  518. ;    Conduct error checking by (1) checking Carry Flag and (2) comparing
  519. ;    number of characters sent with number of characters desired sent.
  520.  
  521.     jc    FPTS1            ; Error return for PC-DOS?
  522.     pop    cx            ; Recover STRING length
  523.     cmp    cx,ax            ; Were all chars sent?
  524.     je    FPTS2            ; Yes, return normally
  525.  
  526. ;-----------------------------
  527. ;    Set up for return
  528.  
  529. FPTS1:    stc                ; Error detected. Set CF
  530.     jmp    short FPTS3        ; Jump to return
  531. FPTS2:    clc                ; Normal return, ensure CF clear
  532. FPTS3:    pop    bp            ; Modified return logic
  533.     ret                ; Return
  534. FPUTS    endp
  535.  
  536. ;-------------------
  537. ;    Check to see if DOS is 2.0+. If not, display passed error message
  538. ;    and terminate program.
  539.  
  540. ISDOS2    proc    near
  541.  
  542. ;-------------------
  543. ;    Request DOS version
  544.  
  545.     mov    ah,30h            ; Request DOS version
  546.     int    21h            ; Call PC-DOS
  547.     cmp    al,2            ; Is it DOS 2.0+
  548.  
  549. ;-------------------
  550. ;    If it is not, just to ERROR.  If it is, return correcting stack
  551. ;     for pushed Error Message address
  552.  
  553.     jb    ID1            ; No, go print error msg/terminate
  554.     ret                ; Yes, return to calling procedure
  555.  
  556. ;-------------------
  557. ;    Print Error Message
  558.  
  559. ID1:    mov    ah,9            ; Request DOS print to screen
  560.     mov    bp,sp            ; Move stack ptr to BP
  561.     mov    dx,[bp + 2]        ; Load Error Msg addr in DX
  562.     int    21h            ; Call PC-DOS
  563.  
  564. ;-------------------
  565. ;    Terminate Program
  566.  
  567.     int    20h            ; Terminate program
  568.  
  569. ;-------------------
  570. ;    Put on ending amenities needed by MASM
  571.  
  572. ISDOS2    endp
  573.  
  574. ;----------------------------
  575. ;    Copy one string into another.
  576.  
  577. STRCPY_PARMS    struc            ;Passed argument structure
  578.     dw    ?,?            ; Saved BP, and return addr IP
  579. DEST    dw    ?            ; Addr of destination string
  580. SOURCE    dw    ?            ; Addr of source string
  581. STRCPY_PARMS    ends
  582.  
  583. STRCPY    proc    near
  584.     @ENTRY                ; Std entry logic
  585.     
  586. ;----------------------------
  587. ;    Set up SI and DI registers with the addresses of the source and 
  588. ;    destination strings
  589.  
  590.     mov    di,[bp].DEST        ; Store dest string addr in DI
  591.     mov    si,[bp].SOURCE        ; Store source string addr in SI
  592.  
  593. ;----------------------------
  594. ;    Copy the string
  595.  
  596. STRP1:    lodsb                ; Get the next byte
  597.     stosb                ; Store it in destination string
  598.     cmp    al,0            ; Was it EOS?
  599.     jne    STRP1            ; No, continue transfer
  600.         
  601. ;----------------------------
  602. ;    Set up for return with addr of dest string in AX
  603.  
  604.     mov    ax,[bp].DEST
  605.     pop    bp            ; Restore BP
  606.     ret                ; Return
  607. STRCPY    endp
  608.  
  609. ;----------------------------
  610. ;    Determine the length of the passed ASCIIZ string.
  611.  
  612. STRLEN_PARMS struc            ; STRUCTURE for passed arguments
  613.     dw    ?            ; BP (saved by std entry logic)
  614.     dw    ?            ; IP (return offset)
  615. ADDRESS dw    ?            ; Passed offset to string
  616. STRLEN_PARMS ends
  617.  
  618. STRLEN    proc    near
  619.     push    bp            ; Standard entry logic
  620.     mov    bp,sp
  621.  
  622. ;----------------------------
  623. ;    Load offset to string into DI and SI
  624.  
  625.     mov    di,[bp].ADDRESS        ; Load offset into DI
  626.     mov    si,di            ; Dup offset in SI
  627.     
  628. ;----------------------------
  629. ;    Find EOS (Null byte).
  630.  
  631.     cld                ; Clear direction flag
  632.     mov    cx,-1            ; Load -1 into CX so not to limit scabs
  633.     xor    al,al            ; AL = EOS
  634.     repne    scasb            ; Find EOS
  635.     dec di                ; DI => EOS
  636.  
  637. ;----------------------------
  638. ;    Calculate length in AX and leave for return.
  639.  
  640.     mov    ax,di            ; AX = EOS
  641.     sub    ax,si            ; Subtract where string starts.
  642.     
  643. ;----------------------------
  644. ;    Set up for return.
  645.  
  646.     mov    sp,bp            ; Standard departure logic
  647.     pop    bp
  648.     ret
  649.     
  650. STRLEN    endp
  651. CSEG    ends
  652.     end  MAIN
  653.